package com.xiaoxie.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.DateSerializer;
import lombok.extern.slf4j.Slf4j;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author xiaoxie
 * @create 2025-01-19
 * @Version 1.0。0
 * @Description: Json工具类
 */
@Slf4j
public class JSONUtils {
    public static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        // 设置日期格式
        OBJECT_MAPPER.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        // 设置时区
        OBJECT_MAPPER.setTimeZone(TimeZone.getTimeZone("GMT+8"));

        // 忽略空字段
        OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);

        // 处理循环引用
        OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
        OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        OBJECT_MAPPER.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
        OBJECT_MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

        // 自定义序列化
        SimpleModule module = new SimpleModule();
        module.addSerializer(Date.class, new DateSerializer());
        OBJECT_MAPPER.registerModule(module);
    }

    /**
     * 将对象转换为JSON字符串
     * @param obj 需要转换的对象
     * @return JSON字符串
     */
    public static String toJson(Object obj) {
        try {
            return OBJECT_MAPPER.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            log.info("对象转为Json字符串失败,", e);
            throw new RuntimeException("Failed to convert object to json string", e);
        }
    }

    /**
     * 将JSON字符串转换为指定类型的对象
     * @param json JSON字符串
     * @param clazz 目标对象的Class类型
     * @param <T> 目标对象的类型
     * @return 转换后的对象
     */
    public static<T> T toBean(String json, Class<T> clazz) {
        try {
            return OBJECT_MAPPER.readValue(json, clazz);
        } catch (Exception e) {
            log.info("Json字符串转为对象失败,", e);
            throw new RuntimeException("Failed to convert JSON to Object", e);
        }
    }

    /**
     * 取出json中的某个指定的节点，并转为指定类型的List
     */
    public static<T> List<T> getNodeAsList(String json, List<String> location) {
        if(location == null || location.isEmpty()) {
            throw new RuntimeException("指定要获取json数据的节点为空！！");
        }
        try {
            // 整个json转为JsonNode
            JsonNode rootNode = OBJECT_MAPPER.readTree(json);
            JsonNode targetNode = null;
            for (String node : location) {
                if(rootNode.has(node)) {
                    rootNode = rootNode.get(node);
                } else {
                    throw new IllegalArgumentException("指定节点" + node + "不存在！！");
                }
            }
            if(rootNode == null) {
                throw new IllegalArgumentException("指定节点不存在！！");
            }
            if(!rootNode.isArray()) {
                throw new IllegalArgumentException("指定节点不是数组！！");
            }
            TypeReference<List<T>> typeReference = new TypeReference<>() {};
           return OBJECT_MAPPER.convertValue(rootNode, typeReference);
        } catch (Exception e) {
            log.info("Json字符串转为List失败,", e);
            throw new RuntimeException("Json字符串转为List失败");
        }
    }
}
